/**
 * @brief MQTT过滤器实现。这是一个终端过滤器。这个模块采用paho.mqtt.cpp模块作为MQTT协议协议层。
 * @version 1.0
 * @date 2018-11-6
 * @author 宋炜
*/
#ifndef MQTT_HPP
#define MQTT_HPP

#include <string>

#include <async_client.h>
#include <connect_options.h>
#include <ssl_options.h>
#include <callback.h>

#include "config.hpp"
#include "misc.h"
#include "filterio.h"
#include "ary_str.hpp"
#if ENABLE_MQTT == 1
class filterList;
class MQTT: public filterIO
{
public:
	enum err_code{

	};
    	class cbs : public mqtt::callback
    	{
    	private:
        	MQTT * ptOwner;
    	public:
        	cbs( MQTT * owner )
        	{
            		ptOwner = owner;
        	}
        	cbs( const MQTT& b )
        	{
            		ptOwner = ptOwner;
        	}
        	virtual ~cbs();

        	cbs& operator=( const cbs& b )
        	{
            		ptOwner = ptOwner;
            		return *this;
        	}
		/**
		 * @brief 连接回调函数
		 * @param cause , 这个参数只是对操作文字性的描述，并不能区分连接的操作状态
		 */
		void connected (const std::string &cause);
		/**
		 * @brief 连接意外丢失
		 * @param cause
		 */
		void connection_lost (const std::string &cause);
		/**
		 * 接到消息处理
		 * @param msg
		 */
		void message_arrived (mqtt::const_message_ptr msg);
		/**
		 * 传输完成
		 * @param tok
		 */
		void delivery_complete (mqtt::delivery_token_ptr tok);
	};
private:
	ArrayString                 m_sub_topics;           // 订阅主题
	ArrayString                 m_pub_topics;           // 发布主题

	int                         m_qos;                  // QOS
	bool                        m_en_log;               // 是否允许LOG

	std::string                 m_server;               // 服务器址
	int                         m_port;		    // 服务器端口
	std::string                 m_user;                 // 用户帐户
	std::string                 m_pswd;		    // 帐号密码
	std::string                 m_url;		    // URL
	std::string                 m_predir;               
	std::string                 m_cid;
	std::string                 m_uri;
	std::string                 m_dir;
	
	std::atomic< bool >         m_anony;		    // 是否匿名登录
	std::atomic< bool >         m_enable;	 	    // 是否启用MQTT
	std::atomic< bool >         m_useCid;		    // 是否使用Client ID连接
	std::atomic< bool >　　　　　m_useAccount;	     // 是否使用帐号连接

	bool                        m_is_conn;

	mqtt::connect_options       m_opts;
	std::unique_ptr<mqtt::async_client>          m_client;

	std::function< void ( const std::string&  , const char * , size_t )> 	cb_recv;
	std::function< void (err_code ) >	cb_conn;
	std::function< void (err_code ) >       cb_close;
	std::function< void (err_code ) >       cb_send;
private:
	/**
	 * @brief 𥘉始化必需参数
	 */
	void init_params();
	/**
	 * @brief 𥘉始化订阅主题
	 */
	void init_sub();
	/**
	 * @brief 𥘉始化发布主题
	 */
	void init_pub();
	/**
	 * @brief 当连接服务器后，向服务器发送订阅请求
	 */
	void do_sub();
public:
	/**
	 * @brief 构造MQTT模块
	 * @param t ，过滤器类型
	 * @param l ， 数据链的链表
	 * @param url ， 服务器地址，可以使IP地址也可以是域名
	 * @param port , 服务器端口
	 */
	MQTT( io_type t , filterList * l );
	MQTT( const std::string& url , int port , io_type t , filterList * l );
	MQTT( const std::string& uri , const std::string& uid , io_type t , filterList * l );
	virtual ~MQTT();
	/**
	 * @brief 打开MQTT连接
	 * @param url ，服务器地址
	 * @param port ， 服务器监听端口
	 * @param uri ，服务器地址:端口，比如：cloud.sn-iot.com:1883
	 * @return 成功打开返回OK，否则返回错误代码
	 */
	err_code open();
	/**
	 */
	err_code open( const std::string& url , int port );
	/**
	 */
	err_code open( const std::string& uri );
	/**
	 * @brief 关闭连接
	 */
	void close();

	/**
	 * @brief 设置登录参数
	 * @param user ， 用户名
	 * @param pswd ， 用户密码
	 * @param en ， 
	 */
	MQTT& login( const std::string& user , const std::string& pswd , bool en = true );
	/**
	 * @brief 设置登录回调函数
	 * @param fun ， 要设置的回调函数
	 * @reutrn 返回当前对象
	 * @exception 
	 * @note 函数原型:
	 * 	void fun( err_code e );
	 */
	MQTT& OnLogin( std::function< void (err_code ) > fun );
	/**
	 * @brief 设置用户ID
	 * @param 用户ID
	 */
	MQTT& uid( const std::string& uid );
	/**
	 * @brief 设置持久数据目录
	 * @param dir 目录名
	 */
	MQTT& dir( const std::string& dir );
	/**
	 * @brief 订阅
	 * @param topic 订阅主题
	 */
	MQTT& sub( const std::string& topic );
	/**
	 * @brief 设置接受数据回调函数
	 * @param fun
	 * @return
	 * @note 
	 * 	函数原型
	 * 	void fun( err_code e, const std::string& topic , const char * data , size_t len );
	 * 	@brief
	 * 	@param topic	主题
	 * 	@param data	接收到的数据
	 * 	@param len	接收到的长度
	 */
	MQTT& OnRecv( std::function< void ( const std::string&  , const char * , size_t )> fun );
	void OnRecv( const std::string& topic , size_t len , const char * data , filterIO::err_code e );
	/**
	 * @brief 取消订阅
	 */
	MQTT& dissub( const std::string& topic );
	/**
	 * @brief 设置QOS
	 * @param qos
	 */
	MQTT& Qos( int qos );
	/**
	 * @brief 响应连接事𢓐
	 * @param e ， 操作状态
	 */
	void OnConnected( err_code e );
	/**
	 * @brief 发送完成后调用这个函数
	 */
	void OnSend( err_code e );
	/**
	 * @brief 设置发送完后的回调
	 */
	void OnSend( std::function< void (err_code ) > fun );
private:
	bool on_forward( size_t len , const char * date , err_code &err , size_t& rlen , char ** rd );
	bool on_backward( size_t len , const char * data , err_code &err , size_t& rlen , char ** rd  );
};
#endif  // ENABLE_MQTT == 1
#endif // MQTT_HPP
